Prüfungsleistung Data Science & Machine Learning: Salary by job title and country

Author

Mathis, Julia und Jonas

Published

November 13, 2023

1. Vorbereitung

Im folgenden Teil dieser Arbeit werden die Vorbereitungen getroffen, die notwendig sind um die Durchführung des Projekts zu ermöglichen.

https://www.kaggle.com/datasets/amirmahdiabbootalebi/salary-by-job-title-and-country

Zusätzliche Quellen für die Methodik:

https://www.datanovia.com/en/blog/top-r-color-palettes-to-know-for-great-data-visualization/

https://ggplot2.tidyverse.org/reference/

ggplot2 - Elegante R Plots (statistikprofis.com)

Dieses Datenset bietet eine umfassende Sammlung von Gehaltsinformationen aus verschiedenen Branchen und Regionen weltweit. Es enthält Details zu Berufsbezeichnungen, Gehältern, Berufssektoren, geografischen Standorten und mehr, die von seriösen Beschäftigungswebsites und Umfragen stammen. Analysieren Sie diese Daten, um Einblicke in Trends auf dem Arbeitsmarkt zu gewinnen, Vergütungen in verschiedenen Berufen zu vergleichen und informierte Entscheidungen über Ihre Karriere oder Einstellungsstrategien zu treffen. Das Datenset ist zur einfachen Analyse bereinigt und vorverarbeitet und steht unter einer offenen Lizenz für Forschungs- und Datenanalysezwecke zur Verfügung.

1.1 Importieren der benötigten Packages

Code
library(tidyverse)
library(tidymodels)
library(corrplot)
library(explore) 
library(ggplot2)
library(corrplot)
library(dplyr)
library(viridis)

Häufig kommt:
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding: https://cran.rstudio.com/bin/windows/Rtools/ Warning in install.packages : Paket ‘dplyr’ wird gerade benutzt und deshab nicht installiert

Installiere RTools nach Link: https://cran.rstudio.com/bin/windows/Rtools/rtools43/rtools.html

1.2 Einlesen der zu Analysierenden Daten

Der Datensatz, der in diesem Projekt analysiert wird, stammt von der website “Kaggle” und beschreibt das Gehalt nach Job und Land in dem gearbeitet wird.

Code
salary <- read_csv("Salary.csv")
Rows: 6684 Columns: 9
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (4): Gender, Job Title, Country, Race
dbl (5): Age, Education Level, Years of Experience, Salary, Senior

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

2. Erster Überblick der Daten

Um einen ersten Überblick zu erhalten, werden die ersten 10 Zeilen der Tabelle ausgelesen:

Code
head(salary, 10)
# A tibble: 10 × 9
     Age Gender `Education Level` `Job Title`       `Years of Experience` Salary
   <dbl> <chr>              <dbl> <chr>                             <dbl>  <dbl>
 1    32 Male                   1 Software Engineer                     5  90000
 2    28 Female                 2 Data Analyst                          3  65000
 3    45 Male                   3 Manager                              15 150000
 4    36 Female                 1 Sales Associate                       7  60000
 5    52 Male                   2 Director                             20 200000
 6    29 Male                   1 Marketing Analyst                     2  55000
 7    42 Female                 2 Product Manager                      12 120000
 8    31 Male                   1 Sales Manager                         4  80000
 9    26 Female                 1 Marketing Coordi…                     1  45000
10    38 Male                   3 Scientist                            10 110000
# ℹ 3 more variables: Country <chr>, Race <chr>, Senior <dbl>

Mithilfe der “describe_tbl”- Funktion können die generellen Informationen über den Datensatz ermittelt werden.

Code
describe_tbl(salary)
6 684 (6.7k) observations with 9 variables
0 observations containing missings (NA)
0 variables containing missings (NA)
0 variables with no variance

Wie oben zu erkennen, enthält der Datensatz 6684 Instanzen, wovon keine einen Wert ohne Angabe (NA’s) besitzt.

Nun wird ein kurzer Blick auf die Art der Merkmale geholfen. Gibt es kategorische oder nummerische Merkmale innerhalb des Datensatzes?

Code
describe(salary)
# A tibble: 9 × 8
  variable            type     na na_pct unique   min      mean    max
  <chr>               <chr> <int>  <dbl>  <int> <dbl>     <dbl>  <dbl>
1 Age                 dbl       0      0     41    21     33.6      62
2 Gender              chr       0      0      2    NA     NA        NA
3 Education Level     dbl       0      0      4     0      1.62      3
4 Job Title           chr       0      0    129    NA     NA        NA
5 Years of Experience dbl       0      0     37     0      8.08     34
6 Salary              dbl       0      0    437   350 115307.   250000
7 Country             chr       0      0      5    NA     NA        NA
8 Race                chr       0      0     10    NA     NA        NA
9 Senior              dbl       0      0      2     0      0.14      1
Wie bereits oben in der Tabelle zu erkennen gibt es Innerhalb des Datensatzes nur zwei verschiedene Datentypen. Die Felder *Age, Education Level, Years of Experience, Salary, Senior* sind nummerische Merkmale. Die Felder Gender, Job Title, Country, Race sind kategorische Merkmale.
Spalte Typ Bedeutung
Age Numerisch Alter
Gender Kategorisch Geschlecht
Education Level Numerisch Bildungsgrad
Job Title Kategorisch Jobtitel
Years of Experience Numerisch Arbeitserfahrung in Jahren
Salary Numerisch Gehalt
Country Kategorisch Land
Race Kategorisch Ethnizität
Senior Numerisch Senior position ja(1)/nein(0)

2.1 Bedeutung von Spalten und Datentypen

Im folgenden Abschnitt werden verschiedene Funktionen dafür verwendet, um die Datentypen und Bedeutung der Spalten zu verstehen.

Code
salary <- salary |>
    rename(
      Job.Title = `Job Title`,
      Years.Of.Experience = `Years of Experience`,
      Education.Level = `Education Level`
    )

Hier werden die Spaltennamen der Spalten verändert, welche ein Leerzeichen im Namen haben. Es handelt sich hierbei um die Spalten “Job Title”, “Years of Experience” und “Education level”. Das Leerzeichen wird einfach durch einen Punkt ersetzt. Da noch häufig im Laufe des Projektes auf die Spaltennamen zugegriffen werdne muss, wird Uns das in der Zukunft noch Zeit sparen.

Nun werfen verschaffen Wir uns einen Überblick über die prozentuale Verteilung der Jobtitel. Aus der Grafik geht hervor, dass der Beruf des “Data Scientist” der meist ausgeführte Beruf ist. Außerdem gibt es innerhalb des Datensatzes auch viele “Data Analsysten” , sowie auch “Backend Devolper”.

Code
explore (salary, Job.Title)

Altersverteilung:

Code
# Erstelle eine Histogramm-Visualisierung der Altersverteilung
ggplot(salary, aes(x = Age)) +
  geom_histogram(binwidth = 5, fill = "skyblue", color = "black", alpha = 0.8) +
  labs(title = "Age Distribution",
       x = "Age",
       y = "Frequency")

Verteilung des Bildungsniveaus

Code
# Definiere eine Farbpalette mit 4 verschiedenen Farben
my_colors <- c("skyblue", "lightgreen", "salmon", "gold") # Farben nach Wunsch ändern

# Erstelle ein Balkendiagramm mit unterschiedlichen Farben für jede Stange basierend auf dem Bildungsniveau
ggplot(salary, aes(x = factor(`Education.Level`))) +
  geom_bar(fill = my_colors, color = "black") +
  labs(title = "Verteilung des Bildungsniveaus",
       x = "Bildungsniveau",
       y = "Anzahl") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Verteilung der Arbeitserfahrung in Jahren

Ab hier wurde Teilweise das Paket “Viridis” für die farbliche Darstellung verwendet um eine Alternative zur Manuellen Deklaration der Farben aufzuzeigen.

Code
# Erstelle ein Histogramm für die Verteilung der Jahre an Erfahrung
ggplot(salary, aes(x = `Years.Of.Experience`)) +
  geom_histogram(binwidth = 5, fill = viridis(8), color = "black") +
  labs(title = "Verteilung der Berufserfahrung",
       x = "Jahre an Erfahrung",
       y = "Häufigkeit") +
  theme_minimal()

Verteilung der Geschlechter

Code
# Erstellen des Diagramms
ggplot(salary, aes(x=Gender)) +
  geom_bar(fill=viridis(2)) +
  ggtitle("Gender Distribution") +
  xlab("Gender") +
  ylab("Count") +
  theme(plot.title = element_text(hjust = 0.5))

Verteilung der Länder

(Alternative Nutzung des Farbschemas)

Code
# Erstellen des Diagramms
ggplot(salary, aes(x = Country, fill = Country)) +
  geom_bar() +
  scale_fill_viridis(discrete = TRUE) +
  ggtitle("Country Distribution") +
  xlab("Country") +
  ylab("Count") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Verteilung der Ethnizitäten

Code
# Erstellen des Diagramms
ggplot(salary, aes(x = Race, fill = Race)) +
  geom_bar() +
  scale_fill_viridis(discrete = TRUE) +
  ggtitle("Race Distribution") +
  xlab("Race") +
  ylab("Count") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Verteilung der 10 Häufigsten Job Titel

Code
# Die Top 10 Jobtitel auswählen
top_job_titles <- names(sort(table(salary$Job.Title), decreasing = TRUE)[1:10])

# Zufällige Farben für jeden Jobtitel generieren
job_colors <- rainbow(length(top_job_titles))

# Daten filtern und ggplot erstellen
ggplot(salary[salary$Job.Title %in% top_job_titles, ], aes(x = factor(Job.Title, levels = top_job_titles), fill = factor(Job.Title))) +
  geom_bar(fill=viridis(10)) +
  scale_fill_manual(values = job_colors) +
  labs(title = "Top 10 Job Titles Distribution",
       x = "Job Title",
       y = "Count") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

2.2 Grundlegende Statistische Merkmale des Datensatzes

Zunächst wird mithilfe der Funktion “summary( )” ein allgemeiner Überblick über die wichtigsten charackteristeischen Merkmale der einzelnen Splaten gegeben.

Code
summary(salary)
      Age           Gender          Education.Level  Job.Title        
 Min.   :21.00   Length:6684        Min.   :0.000   Length:6684       
 1st Qu.:28.00   Class :character   1st Qu.:1.000   Class :character  
 Median :32.00   Mode  :character   Median :1.000   Mode  :character  
 Mean   :33.61                      Mean   :1.622                     
 3rd Qu.:38.00                      3rd Qu.:2.000                     
 Max.   :62.00                      Max.   :3.000                     
 Years.Of.Experience     Salary         Country              Race          
 Min.   : 0.000      Min.   :   350   Length:6684        Length:6684       
 1st Qu.: 3.000      1st Qu.: 70000   Class :character   Class :character  
 Median : 7.000      Median :115000   Mode  :character   Mode  :character  
 Mean   : 8.078      Mean   :115307                                        
 3rd Qu.:12.000      3rd Qu.:160000                                        
 Max.   :34.000      Max.   :250000                                        
     Senior      
 Min.   :0.0000  
 1st Qu.:0.0000  
 Median :0.0000  
 Mean   :0.1435  
 3rd Qu.:0.0000  
 Max.   :1.0000  

Hier alles genauer beschreiben

Erkennbar hier ist es, dass es innerhalb des Datensatzes ein durchschnittliches Alter von 32 Jahren vorliegt. Das Alter streckt sich von 21 Jahren bis zu 62 Jahren. Außerdem gibt es beim “Education-Level” Werte zwischen 1, 2 und 3, wobei der Durchschnitt jedoch bei 1 liegt. Außerdem gibt es bei der Berufserfahrung ( Years of Experience) Werte zwischen 0 bis zu 34 Jahren. Der Median hier beträgt 7.

3. Umstrukturierung des Datensatzes zwecks Visualisierung

Im folgenden wird der Datensatz temporär umstrukturiert um den Datensatz besser analysieren und visualieren zu können.

Ein neuer Wert Namens “Value” wird erschaffen.

Code
Salary_long <- select(salary, -Job.Title, -Gender, -Race, -Country, -Senior)
Salary_long <- pivot_longer(Salary_long, colnames(Salary_long))
Salary <- as.data.frame(Salary_long) 
head(Salary_long)
# A tibble: 6 × 2
  name                value
  <chr>               <dbl>
1 Age                    32
2 Education.Level         1
3 Years.Of.Experience     5
4 Salary              90000
5 Age                    28
6 Education.Level         2

Insgesamt werden in diesem Codechunk die Spalten die nicht nummerische Merkmale sind entfernt und der verbleibende Datensatz wird von einem breiten in ein längeres Format umgewandelt.

Hier kann man folgende Dinge erkennen:

  • Age, Years of Experience und Education Level sind Linksschief und haben ggf. Bedarf einer Transformation für ML-Modelle

  • Age und Years of Experience haben Extrempunkte im oberen Wertebereich, während Salary einer gleichmäßigen Verteilung folgt

Aufgrund der guten Strukturierung der Daten ,eignen sie sich dem ersten Anschein nach gut für eine Ausführliche Explorative Analyse.

3.1 Kategorisierung von Gehalt

Zunächst werden die Daten aus dem Ausgangsdatensatz in einen finalen Datensatz “salary_final” geschrieben.

Code
salary_final <- salary

Durch den Befehl “hist()” wird ein Histogramm erstellt . Es ermöglicht eine visuelle Darstellung der Häufigkeitsverteilung dieses GEhlatsdaten, indem es zeigt, wie oft bestimmte Gehaltsbereiche vorkommen.

Verteilung des Gehalts

Code
# Erstelle ein Histogramm für die Gehaltsverteilung
ggplot(salary, aes(x = Salary)) +
  geom_histogram(binwidth = 10000, fill = viridis(26), color = "black") +
  labs(title = "Gehaltsverteilung",
       x = "Gehalt",
       y = "Häufigkeit") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(labels = scales::comma) +
  theme_minimal()

Im folgenden wird eine neue Spalte “SalaryKat” erstellt die kategorische Werte basdierend auf den Gehältern enthält…

Code
salary_final$SalaryKat <- cut(salary_final$Salary, 
                  breaks = c(-Inf, 50000, 100000, 150000, 200000, 250000, Inf),                      labels = c("50000", "100000", "150000", "200000","250000", "300000"))
Code
# Erstellen des Balkendiagramms für die 5 Gategorien des Gehalts
ggplot(salary_final, aes(x = SalaryKat, fill = SalaryKat)) +
  geom_bar() +
  scale_fill_viridis(discrete = TRUE) +
  ggtitle("Verteilung der Gehaltskategorien") +
  xlab("Gehaltskategorie") +
  ylab("Anzahl") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

3.2 Korrelationen

Im Folgenden werden die Korrelationen zwischen den Verschiedenen Spalten errechnet.

Die Berechnung von Korrelationen ermöglicht es, die Stärke und Richtung des Zusammenhangs zwischen zwei Variablen zu quantifizieren. Dies hilft bei der Modellvalisierung, um potenzielle Probleme, wie zum Beispiel die Multikollinearität zu erkennen.

Nun werden verschiedene Korrelationen errechnet:

Code
# Korrelation zwischen Salary und Years.Of.Experience berechnen
correlation_salary_experience <- cor(salary_final$Salary, salary_final$Years.Of.Experience)

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Salary und Years.Of.Experience ist:", correlation_salary_experience, "\n")
Die Korrelation zwischen Salary und Years.Of.Experience ist: 0.8109416 

“Hier würde Ich keinen Text vorschreiben, Ausgabe aussagekräftig genug”

Code
# Korrelation zwischen Salary und Age berechnen
correlation_salary_age <- cor(salary_final$Salary, salary_final$Age, use = "complete.obs")

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Salary und Age ist:", correlation_salary_age, "\n")
Die Korrelation zwischen Salary und Age ist: 0.7283429 

“Hier würde Ich keinen Text vorschreiben, Ausgabe aussagekräftig genug”

Code
# Korrelation zwischen Years.Of.Experience und Age berechnen
correlation_experience_age <- cor(salary_final$Years.Of.Experience, salary_final$Age, use = "complete.obs")

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Years.Of.Experience und Age ist:", correlation_experience_age, "\n")
Die Korrelation zwischen Years.Of.Experience und Age ist: 0.9376094 

“Hier würde Ich keinen Text vorschreiben, Ausgabe aussagekräftig genug”

Code
# Korrelation zwischen Seniority und Years.Of.Experience berechnen
correlation_seniority_experience <- cor(salary_final$Senior, salary_final$Years.Of.Experience, use = "complete.obs")

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Seniority und Years.Of.Experience ist:", correlation_seniority_experience, "\n")
Die Korrelation zwischen Seniority und Years.Of.Experience ist: 0.3178772 

das ergebnis der correlationen: von salary und years.of.experience ist es 0.81 von Salary und Age ist es 0.73 und die von Age und Years.Of.Experience ist 0.93 wie kommt so ein starker unterschied zu stande bei den werten im vergleich zu salary obwohl sie doch eine hohe correlation zueinander haben

Verteilung der Daten: Es ist möglich, dass die Verteilung der Daten in den Variablen “Age” und “Years.Of.Experience” anders ist als in der Variable “Salary”. Wenn die Daten in “Age” und “Years.Of.Experience” breiter gestreut sind, kann dies zu einer geringeren Korrelation führen, selbst wenn eine starke lineare Beziehung besteht.

Nicht-lineare Beziehung: Die Korrelation misst nur lineare Beziehungen. Wenn die Beziehung zwischen “Age” und “Years.Of.Experience” nicht linear ist, könnte dies zu einem niedrigeren Korrelationswert führen.

Ausreißer: Das Vorhandensein von Ausreißern kann die Korrelation beeinflussen. Wenn es Ausreißer in einer der Variablen gibt, kann dies den Korrelationswert beeinträchtigen.

Stichprobengröße: Bei kleineren Stichproben können Korrelationswerte instabiler sein.

4. Tests für die Thesen

Im folgenden werden anhand der Daten ein paar Tests durchgeführt um Aussagen für die Thesen heruaszufiltern. Dies geschieht mithilfe einer Visualisierung der Beziehungen zwischen den verschiedenen Spalten, sowie mitihilfe von Korrelationen.

4.1 Korrelationen

Das Ergebnis dieses Codechunks ist eine Darstellung der Korrelationsmatrix:

Code
correlations <- cor(salary_final[, c("Age", "Education.Level", "Years.Of.Experience", "Salary")])

print(correlations)
                          Age Education.Level Years.Of.Experience    Salary
Age                 1.0000000       0.5963804           0.9376094 0.7283429
Education.Level     0.5963804       1.0000000           0.6131650 0.6454436
Years.Of.Experience 0.9376094       0.6131650           1.0000000 0.8109416
Salary              0.7283429       0.6454436           0.8109416 1.0000000

Erkennbar hier ist eine starke Korrelation zwischen dem Alter und den “Years of Experience”. Desweiteren liegt auch eine starke Korrelation zwischnem den Years of Experience und dem entgültigen Gehalt. Eine nicht so starke Korrelation liegt zwischen dem Alter und dem Education Level mit einem Wert von ungefähr 0,6.

Code
filtered_data_numeric <- select(salary, Salary, Age, Years.Of.Experience, Education.Level)
glimpse(filtered_data_numeric)
Rows: 6,684
Columns: 4
$ Salary              <dbl> 90000, 65000, 150000, 60000, 200000, 55000, 120000…
$ Age                 <dbl> 32, 28, 45, 36, 52, 29, 42, 31, 26, 38, 29, 48, 35…
$ Years.Of.Experience <dbl> 5, 3, 15, 7, 20, 2, 12, 4, 1, 10, 3, 18, 6, 14, 2,…
$ Education.Level     <dbl> 1, 2, 3, 1, 2, 1, 2, 1, 1, 3, 2, 1, 1, 2, 1, 1, 2,…
Code
cor(filtered_data_numeric)
                       Salary       Age Years.Of.Experience Education.Level
Salary              1.0000000 0.7283429           0.8109416       0.6454436
Age                 0.7283429 1.0000000           0.9376094       0.5963804
Years.Of.Experience 0.8109416 0.9376094           1.0000000       0.6131650
Education.Level     0.6454436 0.5963804           0.6131650       1.0000000
Code
#Erstellen des Korrelationplots
corrplot(cor(filtered_data_numeric), method = "ellipse", col = viridis(200))

4.2 Streudiagramme

Code
#Erstellen des Streudiagrammes
ggplot(salary_final, aes(x = Years.Of.Experience, y = Salary)) +
  geom_point(color = viridis(2)[1], size = 3, shape = 16) +
  labs(title = "Streudiagramm von Berufserfahrung vs. Gehalt",
       x = "Berufserfahrung",
       y = "Gehalt")

In diesem Streudiagramm ist erkennbar, das es einen eindeutigen Trend nach oben gibt je mehr “Years of Experience” vorliegen. So ist auch zu sehen, dass die Topgehälter von 250.000€ zwischen 20 bis 30 Erfahrungsjahren liegen.

Code
ggplot(salary_final, aes(x = Education.Level, y = Salary)) +
  geom_point(color = viridis(2)[1], size = 3, shape = 16) +
  labs(title = "Scatter Plot of Education Level vs Salary",
       x = "Years of Experience",
       y = "Salary")

Die vorliegende Datenanalyse zeigt einen klaren Trend zu höheren Gehaltsklassen, der mit einem Anstieg des Bildungsniveaus einhergeht. Diese Tendenz wird durch eine höhere Dichte in den oberen Gehaltsgruppen für Personen mit dem dritten Bildungsgrad im Vergleich zum zweiten und ersten Bildungsgrad deutlich.

4.3 Balkendiagramme mit 2 Variablen

In diesem Abschnitt werden Balkendiagramme verwendet um den Datensatz auf Beziehungen zu analysieren.

4.3.1 Average Salary by Race

Code
#Erstellen des Diagramms
ggplot(salary_final, aes(x = Race, y = Salary, fill = Race)) +
  stat_summary(fun = "mean", geom = "bar") +
  scale_fill_viridis(discrete = TRUE) +
  ggtitle("Durchschnittliches Gehalt nach Ethnizität") +
  xlab("Rasse") +
  ylab("Durchschnittliches Gehalt")

Die Grafik macht deutlich, dass die Gruppen “Black, Korean, Mixed und White” im Durchschnitt am meisten verdienen.

4.3.2 Average Salary by Country

Code
ggplot(salary_final, aes(x = Country, y = Salary, fill = Country)) +
  stat_summary(fun = "mean", geom = "bar", position = "dodge", color = "black") +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Durchschnittliches Gehalt nach Land",
       x = "Land",
       y = "Durchschnittliches Gehalt") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Es ist ersichtlich, dass in den Ländern “Canada und China” das durchschnittliche Gehalt am größten ist. Jedochg ist zu erwähnen, dass alle Länder nah bei einander liegen.

4.3.3 Average Salary by Country and Gender

In diesem Fall wird ein gestapeltes Balkendiagramm erstellt. Die Balken sind nach Geschlecht gruppiert und gestapelt. DIes ermöglicht einen Vergleich der durchschnittlichen Gehälter zwischen den Ländern und Geschlechtern

Code
ggplot(salary_final, aes(x = Country, y = Salary, fill = Gender)) +
  geom_bar(stat = "summary", fun = "mean", position = "stack", color = "black") +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Average Salary by Country and Gender",
       x = "Country",
       y = "Average Salary") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) 

Hier ist zu erkennen, das alle Länder ungefähr die gleiche Verteilung zwischen “Male” und “Female” haben.

4.3.4 Average Salary by Country and Education Level

Zur Visualisierung der durchnittlichen Bezahlung für Länder und Bildungsniveau wird ein gruppiertes Balkendiagramm verwendet. DIe Balken sind nach Bildungsniveau und nebeneinander gruppiert.

Desweiteren sind zur besseren Veranschaulichung die Beschriftungen auf der X-Achse um 45 Grad gedreht.

Code
ggplot(salary_final, aes(x = Country, y = Salary, fill = factor(Education.Level))) +
  geom_bar(stat = "summary", fun = "mean", position = "dodge", color = "black") +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Average Salary by Country and Education Level",
       x = "Country",
       y = "Average Salary") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))  

Es ist deutlich zu erkennen, dass die Gehälter in jedem Land deutlich ansteigen je höher das Bildungsniveau ist.

4.3.5 Average Salary by Country and Race

Auch hier wird zum Vergleich der durchschnittlichen Gehälter zwischen den Ländern und ethnischen Gruppen, ein gestapeltes Balkendiagramm erstellt. Die Balken sind nach ethnischer Gruppe gruppiert und gestapelt.

Code
ggplot(salary_final, aes(x = Country, y = Salary, fill = Race)) +
  geom_bar(stat = "summary", fun = "mean", position = "stack", color = "black") +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Average Salary by Country and Race",
       x = "Country",
       y = "Average Salary") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) 

!!!!! Salary passt nicht!!!!!!!

Hier ist deutlich sichtbar, dass nicht in jedem Land logischerweise jede ethnische Gruppe vertreten ist. So sind nur in 2 Ländern mehr als 3 verschiedene Gruppen in diesem Datensatz aufgeführt

4.3.6 Average Salary by Job Title

Code
ggplot(salary_final, aes(x = Job.Title, y = Salary)) +
  geom_bar(stat = "summary", fun = "mean", color = viridis(2)[1], color = viridis(2)[1]) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Average Salary by Job Title",
       x = "Job Title",
       y = "Average Salary") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))  
Warning: Duplicated aesthetics after name standardisation: colour

Hier wird festgestellt das in dem Datensatz zu viele Jobtitle vorkommen

Code
job_title_count <- table(salary_final$Job.Title)
print(job_title_count)

               Account Executive                  Account Manager 
                               1                                4 
                      Accountant         Administrative Assistant 
                               6                                2 
         Advertising Coordinator               Back end Developer 
                               1                              242 
                Business Analyst   Business Development Associate 
                              20                                7 
    Business Development Manager    Business Intelligence Analyst 
                               5                                1 
     Business Operations Analyst                              CEO 
                               2                                1 
              Chief Data Officer         Chief Technology Officer 
                               1                                1 
                      Consultant        Content Marketing Manager 
                               1                               73 
                      Copywriter                Creative Director 
                               2                                1 
        Customer Service Manager             Customer Service Rep 
                               2                                1 
 Customer Service Representative         Customer Success Manager 
                               6                                1 
            Customer Success Rep      Customer Support Specialist 
                               1                                1 
                    Data Analyst                    Data Engineer 
                             391                                4 
                Data Entry Clerk                   Data Scientist 
                               1                              515 
                 Delivery Driver                         Designer 
                               5                                1 
                       Developer         Digital Content Producer 
                               1                                1 
       Digital Marketing Manager     Digital Marketing Specialist 
                              52                               15 
                        Director Director of Business Development 
                               1                                1 
        Director of Data Science          Director of Engineering 
                              57                                2 
             Director of Finance                   Director of HR 
                               2                               69 
       Director of Human Capital      Director of Human Resources 
                               1                                2 
           Director of Marketing           Director of Operations 
                              88                               11 
  Director of Product Management                Director of Sales 
                               1                                1 
 Director of Sales and Marketing                         Engineer 
                               1                                2 
               Event Coordinator                Financial Advisor 
                               2                                5 
               Financial Analyst                Financial Manager 
                              53                              139 
             Front end Developer              Front End Developer 
                             239                               31 
             Full Stack Engineer                 Graphic Designer 
                             304                               23 
               Help Desk Analyst                   HR Coordinator 
                               1                               29 
                   HR Generalist                       HR Manager 
                             104                                5 
                   HR Specialist      Human Resources Coordinator 
                               1                               50 
        Human Resources Director          Human Resources Manager 
                               1                              152 
      Human Resources Specialist                    IT Consultant 
                               1                                2 
                      IT Manager               IT Project Manager 
                               1                                1 
                      IT Support            IT Support Specialist 
                               1                                2 
          Juniour HR Coordinator            Juniour HR Generalist 
                               3                                3 
                         Manager                Marketing Analyst 
                               2                              144 
           Marketing Coordinator               Marketing Director 
                             167                               65 
               Marketing Manager             Marketing Specialist 
                             315                               10 
                Network Engineer                   Office Manager 
                               1                                1 
              Operations Analyst           Operations Coordinator 
                               8                                5 
             Operations Director               Operations Manager 
                               1                              122 
              Principal Engineer              Principal Scientist 
                               1                                1 
                Product Designer      Product Development Manager 
                              80                                1 
                 Product Manager        Product Marketing Manager 
                             323                               70 
             Project Coordinator                 Project Engineer 
                               5                              317 
                 Project Manager         Public Relations Manager 
                              34                                1 
       Quality Assurance Analyst                     Receptionist 
                               1                               57 
                       Recruiter                Research Director 
                               3                               75 
              Research Scientist                       Researcher 
                             119                                1 
                 Sales Associate                   Sales Director 
                             212                               62 
                 Sales Executive                    Sales Manager 
                              38                               58 
        Sales Operations Manager             Sales Representative 
                               1                               81 
                       Scientist                 Social Media Man 
                               3                                1 
            Social Media Manager          Social Media Specialist 
                              15                                2 
              Software Architect               Software Developer 
                               1                              186 
               Software Engineer        Software Engineer Manager 
                             809                              376 
                Software Manager         Software Project Manager 
                               1                                1 
             Strategy Consultant             Supply Chain Analyst 
                               1                                1 
            Supply Chain Manager              Technical Recruiter 
                               1                                1 
    Technical Support Specialist                 Technical Writer 
                               1                                1 
             Training Specialist                      UX Designer 
                               2                                5 
                   UX Researcher                    VP of Finance 
                               1                                1 
                VP of Operations                     Web Designer 
                               1                                1 
                   Web Developer 
                             129 

Hier nochmal das obere genauer grafisch herausgearbeitet

Code
job_title_count <- table(salary_final$Job.Title)
job_title_df <- data.frame(Job_Title = names(job_title_count), Frequency = as.numeric(job_title_count))

ggplot(job_title_df, aes(x = Job_Title, y = Frequency)) +
  geom_bar(stat = "identity", fill = viridis(2)[1], color = "black") +
  labs(title = "Frequency of Unique Job Titles",
       x = "Job Titles",
       y = "Frequency") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) 

Jeder Job Dargestellt. Es ist zu notieren das es nicht möglich ist die Vielzahl der unterschiedlichen Jobs darzustellen.

Code
library(dplyr)

# Zählen der Vorkommen für jeden Jobtitel
job_title_count <- salary %>%
  count(`Job.Title`, sort = TRUE)
job_title_count
# A tibble: 129 × 2
   Job.Title                     n
   <chr>                     <int>
 1 Software Engineer           809
 2 Data Scientist              515
 3 Data Analyst                391
 4 Software Engineer Manager   376
 5 Product Manager             323
 6 Project Engineer            317
 7 Marketing Manager           315
 8 Full Stack Engineer         304
 9 Back end Developer          242
10 Front end Developer         239
# ℹ 119 more rows

4.4 Boxplots

Code
ggplot(salary_final, aes(x = Country, y = Salary, fill = Race)) +
  geom_boxplot() +
  scale_fill_viridis(discrete = TRUE) +
  stat_summary(fun = "median", geom = "point", shape = 18, size = 3, color = "red", position = position_dodge(width = 0.75)) +
  labs(title = "Salary Distribution by Country and Race",
       x = "Country",
       y = "Salary") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))  

5. Daten Aufbereiten

(Tests der Thesen gibt uns die Antwort darauf wie die Daten aufbereitet werden müssen)

5.1 Jobs

Da in dem Datensatz teilweise Jobs nur einmalig vertreten sind, kann ein erhebliches Stichproben-Bias verursacht werden. Da das mittlere Einkommen ein wichtiges Merkmal in unserer explorativen Datenanalyse darstellt und mindestens 30 Einträge für eine aussagekräftige Stichprobe nötig sind, haben wir uns dazu entschlossen alle Einträge mit N<30 bei der Anzahl der Jobtitel (N) abzuschneiden.

Code
filtered_data <- salary_final %>%
  group_by(Job.Title) %>%
  summarise(job_count = n()) %>%
  filter(job_count > 30) %>%
  inner_join(salary_final, by = "Job.Title")

print(filtered_data)
# A tibble: 6,398 × 11
   Job.Title   job_count   Age Gender Education.Level Years.Of.Experience Salary
   <chr>           <int> <dbl> <chr>            <dbl>               <dbl>  <dbl>
 1 Back end D…       242    33 Female               2                   5 110000
 2 Back end D…       242    32 Male                 1                   4  95000
 3 Back end D…       242    26 Female               2                   3  90000
 4 Back end D…       242    26 Female               2                   2  70000
 5 Back end D…       242    24 Female               1                   1  60000
 6 Back end D…       242    26 Female               2                   3  90000
 7 Back end D…       242    24 Female               2                   1  60000
 8 Back end D…       242    34 Male                 2                   6 125000
 9 Back end D…       242    29 Female               1                   3  85000
10 Back end D…       242    23 Male                 1                   1  55000
# ℹ 6,388 more rows
# ℹ 4 more variables: Country <chr>, Race <chr>, Senior <dbl>, SalaryKat <fct>
Code
job_title_count <- table(filtered_data$Job.Title)
print(job_title_count)

         Back end Developer   Content Marketing Manager 
                        242                          73 
               Data Analyst              Data Scientist 
                        391                         515 
  Digital Marketing Manager    Director of Data Science 
                         52                          57 
             Director of HR       Director of Marketing 
                         69                          88 
          Financial Analyst           Financial Manager 
                         53                         139 
        Front end Developer         Front End Developer 
                        239                          31 
        Full Stack Engineer               HR Generalist 
                        304                         104 
Human Resources Coordinator     Human Resources Manager 
                         50                         152 
          Marketing Analyst       Marketing Coordinator 
                        144                         167 
         Marketing Director           Marketing Manager 
                         65                         315 
         Operations Manager            Product Designer 
                        122                          80 
            Product Manager   Product Marketing Manager 
                        323                          70 
           Project Engineer             Project Manager 
                        317                          34 
               Receptionist           Research Director 
                         57                          75 
         Research Scientist             Sales Associate 
                        119                         212 
             Sales Director             Sales Executive 
                         62                          38 
              Sales Manager        Sales Representative 
                         58                          81 
         Software Developer           Software Engineer 
                        186                         809 
  Software Engineer Manager               Web Developer 
                        376                         129 
Code
job_title_count <- table(filtered_data$Job.Title)
job_title_df <- data.frame(Job_Title = names(job_title_count), Frequency = as.numeric(job_title_count))

ggplot(job_title_df, aes(x = Job_Title, y = Frequency)) +
  geom_bar(stat = "identity", fill = viridis(2)[1], color = "black") +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Frequency of Unique Job Titles",
       x = "Job Titles",
       y = "Frequency") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Auf min 30 Jobhäufigkeiten angepasst.

Code
job_title_count_filtered <- table(filtered_data$Job.Title)
cat(paste(names(job_title_count_filtered), ":", job_title_count_filtered, "\n"))
Back end Developer : 242 
 Content Marketing Manager : 73 
 Data Analyst : 391 
 Data Scientist : 515 
 Digital Marketing Manager : 52 
 Director of Data Science : 57 
 Director of HR : 69 
 Director of Marketing : 88 
 Financial Analyst : 53 
 Financial Manager : 139 
 Front end Developer : 239 
 Front End Developer : 31 
 Full Stack Engineer : 304 
 HR Generalist : 104 
 Human Resources Coordinator : 50 
 Human Resources Manager : 152 
 Marketing Analyst : 144 
 Marketing Coordinator : 167 
 Marketing Director : 65 
 Marketing Manager : 315 
 Operations Manager : 122 
 Product Designer : 80 
 Product Manager : 323 
 Product Marketing Manager : 70 
 Project Engineer : 317 
 Project Manager : 34 
 Receptionist : 57 
 Research Director : 75 
 Research Scientist : 119 
 Sales Associate : 212 
 Sales Director : 62 
 Sales Executive : 38 
 Sales Manager : 58 
 Sales Representative : 81 
 Software Developer : 186 
 Software Engineer : 809 
 Software Engineer Manager : 376 
 Web Developer : 129 

5.2 Job Typen

5.2.1 Anzahl der technischen / administrativen Jobs

Im Folgenden werden Jobs auf Basis Ihrer Jobtitel in technische und adminisztrative Kategoerien unterteilt. Danach werden die Datensätze “technische_jobs” und “admin_Jobs” erstellt.

Code
# Filtern nach technischen Jobs
technische_jobs <- filtered_data[grep("data|engineer|developer|analyst|scientist", tolower(filtered_data$Job.Title)), ]

# Filtern nach wirtschaftlichen/administrativen Jobs
admin_jobs <- filtered_data[grep("associate|director|manager|sales|coordinator|generalist|receptionist|designer", tolower(filtered_data$Job.Title)), ]

# Beispiel für die Ausgabe der ersten paar Zeilen der gefilterten Daten
head(technische_jobs)
# A tibble: 6 × 11
  Job.Title    job_count   Age Gender Education.Level Years.Of.Experience Salary
  <chr>            <int> <dbl> <chr>            <dbl>               <dbl>  <dbl>
1 Back end De…       242    33 Female               2                   5 110000
2 Back end De…       242    32 Male                 1                   4  95000
3 Back end De…       242    26 Female               2                   3  90000
4 Back end De…       242    26 Female               2                   2  70000
5 Back end De…       242    24 Female               1                   1  60000
6 Back end De…       242    26 Female               2                   3  90000
# ℹ 4 more variables: Country <chr>, Race <chr>, Senior <dbl>, SalaryKat <fct>
Code
head(admin_jobs)
# A tibble: 6 × 11
  Job.Title    job_count   Age Gender Education.Level Years.Of.Experience Salary
  <chr>            <int> <dbl> <chr>            <dbl>               <dbl>  <dbl>
1 Content Mar…        73    30 Female               1                   3  55000
2 Content Mar…        73    27 Female               2                   4  80000
3 Content Mar…        73    27 Female               2                   4  80000
4 Content Mar…        73    27 Female               2                   4  80000
5 Content Mar…        73    27 Female               2                   4  80000
6 Content Mar…        73    27 Female               2                   4  80000
# ℹ 4 more variables: Country <chr>, Race <chr>, Senior <dbl>, SalaryKat <fct>
Code
# Anzahl der technischen Jobs
anzahl_technische_jobs <- nrow(technische_jobs)
cat("Anzahl der technischen Jobs:", anzahl_technische_jobs, "\n")
Anzahl der technischen Jobs: 3912 
Code
# Anzahl der administrativen Jobs
anzahl_admin_jobs <- nrow(admin_jobs)
cat("Anzahl der administrativen Jobs:", anzahl_admin_jobs, "\n")
Anzahl der administrativen Jobs: 2919 

Zu erkennen ist hier, dass es detlich mehr technische Jobs als administraive Jobs in diesem Datensatz gibt.

???? notwenig nochmal zu wissen wie viele insgesamt in filtered data sind????

Code
# Anzahl der Zeilen (Werte) in filtered_data
anzahl_werte_filtered_data <- nrow(filtered_data)

# Anzeigen der Anzahl der Werte
cat("Anzahl der Werte in filtered_data:", anzahl_werte_filtered_data, "\n")
Anzahl der Werte in filtered_data: 6398 

Insgesamt gibt es in dem gefilterten Datensatz 6398 Einträge, was bedeutet, dass ungefähr 60% technische Jobs und 40% administrative Jobs sind.

Nun wird nochmal der gefilterte Datensatz mit der Summe von “anzahl_technische_jobs” und “anzahl_administraive Jobs” verglichen.

Code
anzahl_jobs <- anzahl_technische_jobs + anzahl_admin_jobs
cat(anzahl_jobs)
6831

Zu erkennen ist hier, dass es zwei unterschiedliche Werte für die Beiden Datensätze gibt.

Wir vermuten, dass einige Jobs doppelt gezählt werden. Dies würde erklären, dass deutlich mehr Einträge in “anzahl_jobs” sind. Unser Lösungsvorschlag wäre hier, dass wir den Jobs IDs geben.

5.2.1.1 Lösungsansatz 1

Der erste Lösungsansatz sieht wie folgt aus:

Die jobs werden basierend auf bestimmten Namen ( data, enginner etc. ) gefiltert und alle Duplikate werden entfernt. Das Ergebnis ist nun ein neuer Datensatz “filtered_data_neu” in dem alle Zeilen außer, die technischen und administrativen Jobs enthält.

Code
# Add ID-Spalte
filtered_data$ID <- 1:nrow(filtered_data)

# Filtern nach technischen Jobs und Entfernen von Duplikaten
technische_jobs2 <- unique(filtered_data[grep("data|engineer|developer|analyst|scientist", tolower(filtered_data$Job.Title)), ])

# Filtern nach wirtschaftlichen/administrativen Jobs und Entfernen von Duplikaten
admin_jobs2 <- unique(filtered_data[grep("associate|director|manager|sales|coordinator|generalist|receptionist|designer", tolower(filtered_data$Job.Title)), ])

# Merke die IDs der übereinstimmenden Zeilen
ids_technische_jobs <- filtered_data$ID[filtered_data$Job.Title %in% technische_jobs2$Job.Title]
ids_admin_jobs <- filtered_data$ID[filtered_data$Job.Title %in% admin_jobs2$Job.Title]

# Entferne die entsprechenden Zeilen aus filtered_data
filtered_data_neu <- filtered_data[!(filtered_data$ID %in% c(ids_technische_jobs, ids_admin_jobs)), ]

# Beispiel für die Ausgabe der ersten paar Zeilen der gefilterten Daten
head(filtered_data_neu)
# A tibble: 0 × 12
# ℹ 12 variables: Job.Title <chr>, job_count <int>, Age <dbl>, Gender <chr>,
#   Education.Level <dbl>, Years.Of.Experience <dbl>, Salary <dbl>,
#   Country <chr>, Race <chr>, Senior <dbl>, SalaryKat <fct>, ID <int>
Code
anzahl_technische_jobs2 <- nrow(technische_jobs2)
cat("Anzahl der technischen Jobs2:", anzahl_technische_jobs2, "\n")
Anzahl der technischen Jobs2: 3912 
Code
anzahl_admin_jobs2 <- nrow(admin_jobs2)
cat("Anzahl der administrativen Jobs2:", anzahl_admin_jobs2, "\n")
Anzahl der administrativen Jobs2: 2919 

Es scheint als würde dieser Lösungsansatz nicht funktionieren, da der neue Datensatz keine Einträge enthält.

5.2.1.2 Lösungsansatz 2

Der zweite Lösungsansatz zum Problem der Klassifizierung der verschiedenen Job Typen kann gelöst werden, indem die beiden Jobs nicht in 2 Tabellen unterteilt werden, sondern Jede Zeile einen Wert des entsprechenden Jobs Typs zugeordnet wird.

Code
# Erstellung der neuen Spalte "job_type" basierend auf den gegebenen Filtern
filtered_data$job_type <- ifelse(
    grepl("data|engineer|developer|analyst|scientist", tolower(filtered_data$Job.Title)),
    0, # 0 für technische Jobs
    ifelse(
        grepl("associate|director|manager|sales|coordinator|generalist", tolower(filtered_data$Job.Title)),
        1, # 1 für administrative Jobs
        NA  # NA für alle anderen
    )
)

# Anzeige der Anzahl aller Zeilen im Datensatz und der Anzahl der Zeilen für jede job_type-Ausprägung
total_rows <- nrow(filtered_data)
count_job_types <- table(filtered_data$job_type, useNA = "ifany")

# Ausgabe der Ergebnisse
print(paste("Gesamtanzahl der Zeilen im Datensatz:", total_rows))
[1] "Gesamtanzahl der Zeilen im Datensatz: 6398"
Code
print("Anzahl der Zeilen für jede job_type-Ausprägung:")
[1] "Anzahl der Zeilen für jede job_type-Ausprägung:"
Code
print(count_job_types)

   0    1 <NA> 
3912 2349  137 

Es wird eine neue Spalte namens “job_type” erstellt. Diese Spalte wird nun mit Werten gefüllt. Der Wert = für Zielen mit technischen Jobs und 1 für administrative Jobs. NA erhalten alle anderen Jobtypen.

Nun werden die eben gefundenen NAs in einen neuen Datensatz geschrieben.

Code
# Auswahl aller Zeilen mit NA-Werten in der Spalte "job_type"
na_job_type_rows <- subset(filtered_data, is.na(job_type))

# Anzeige der ausgewählten Zeilen mit NA in "job_type"
na_job_type_rows
# A tibble: 137 × 13
   Job.Title   job_count   Age Gender Education.Level Years.Of.Experience Salary
   <chr>           <int> <dbl> <chr>            <dbl>               <dbl>  <dbl>
 1 Product De…        80    33 Male                 2                   6  90000
 2 Product De…        80    43 Female               3                  18 140000
 3 Product De…        80    45 Female               3                  15 150000
 4 Product De…        80    45 Female               3                  15 150000
 5 Product De…        80    44 Female               3                  15 150000
 6 Product De…        80    44 Female               3                  15 150000
 7 Product De…        80    27 Male                 1                   3  60000
 8 Product De…        80    27 Male                 1                   3  60000
 9 Product De…        80    27 Male                 1                   3  60000
10 Product De…        80    27 Male                 1                   3  60000
# ℹ 127 more rows
# ℹ 6 more variables: Country <chr>, Race <chr>, Senior <dbl>, SalaryKat <fct>,
#   ID <int>, job_type <dbl>

Das Ergebnis dieser Abfrage ist eine Tabelle, welche nur aus Product Designer % Receptionist besteht. Diese werden nun den adminsitrativen Jobs hinzugefügt.

Code
# Aktualisierung der job_type-Spalte für die spezifischen Job-Titel
filtered_data$job_type[filtered_data$Job.Title %in% c("Product Designer", "Receptionist")] <- 1

# Anzeige der aktualisierten Daten für die ausgewählten Job-Titel
subset(filtered_data, Job.Title %in% c("Product Designer", "Receptionist"))
# A tibble: 137 × 13
   Job.Title   job_count   Age Gender Education.Level Years.Of.Experience Salary
   <chr>           <int> <dbl> <chr>            <dbl>               <dbl>  <dbl>
 1 Product De…        80    33 Male                 2                   6  90000
 2 Product De…        80    43 Female               3                  18 140000
 3 Product De…        80    45 Female               3                  15 150000
 4 Product De…        80    45 Female               3                  15 150000
 5 Product De…        80    44 Female               3                  15 150000
 6 Product De…        80    44 Female               3                  15 150000
 7 Product De…        80    27 Male                 1                   3  60000
 8 Product De…        80    27 Male                 1                   3  60000
 9 Product De…        80    27 Male                 1                   3  60000
10 Product De…        80    27 Male                 1                   3  60000
# ℹ 127 more rows
# ℹ 6 more variables: Country <chr>, Race <chr>, Senior <dbl>, SalaryKat <fct>,
#   ID <int>, job_type <dbl>
Code
# Anzeige der Anzahl aller Zeilen im Datensatz und der Anzahl der Zeilen für jede job_type-Ausprägung
total_rows <- nrow(filtered_data)
count_job_types <- table(filtered_data$job_type, useNA = "ifany")

# Ausgabe der Ergebnisse
print(paste("Gesamtanzahl der Zeilen im Datensatz:", total_rows))
[1] "Gesamtanzahl der Zeilen im Datensatz: 6398"
Code
print("Anzahl der Zeilen für jede job_type-Ausprägung:")
[1] "Anzahl der Zeilen für jede job_type-Ausprägung:"
Code
print(count_job_types)

   0    1 
3912 2486 

Nun ist das Klassifizierungsproblem gelöst. Aufgrund dessen können jetzt auch Diegramme über Job_types ausgewertet werden.

5.3 Expats & Einheimische

Im folgenden werden einige Boxplots erstellt.

5.3.1 Years of Experience vs. Gender

Code
ggplot(filtered_data, aes(x = factor(Gender), y = Years.Of.Experience, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Years of Experience vs. Gender",
       x = "Gender",
       y = "Years of Experience",
       fill = "Gender") +
  theme_minimal()

5.3.2 Years of Experience vs. Gender (China)

Code
# Bibliothek ggplot2 laden
library(ggplot2)

# Daten für China filtern
data_china <- subset(filtered_data, Country == "China")

# Boxplot erstellen
ggplot(data_china, aes(x = factor(Gender), y = Years.Of.Experience, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Years of Experience vs. Gender (China)",
       x = "Gender",
       y = "Years of Experience",
       fill = "Gender") +
  theme_minimal()

5.3.3 Years of Experience vs. Gender( USA)

Code
# Bibliothek ggplot2 laden
library(ggplot2)

# Daten für USA filtern
data_usa <- subset(filtered_data, Country == "USA")

# Boxplot erstellen
ggplot(data_usa, aes(x = factor(Gender), y = Years.Of.Experience, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Years of Experience vs. Gender (USA)",
       x = "Gender",
       y = "Years of Experience",
       fill = "Gender") +
  theme_minimal()

5.3.4 Salary vs. Gender ( China)

Code
# Bibliothek ggplot2 laden
library(ggplot2)

# Daten für China filtern
data_china <- subset(filtered_data, Country == "China")

# Boxplot für Salary vs. Gender erstellen
ggplot(data_china, aes(x = factor(Gender), y = Salary, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Salary vs. Gender (China)",
       x = "Gender",
       y = "Salary",
       fill = "Gender") +
  theme_minimal()

5.3.5 Salary vs. Gender (USA)

Code
# Bibliothek ggplot2 laden
library(ggplot2)

# Daten für USA filtern
data_usa <- subset(filtered_data, Country == "USA")

# Boxplot für Salary vs. Gender erstellen
ggplot(data_usa, aes(x = factor(Gender), y = Salary, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Salary vs. Gender (USA)",
       x = "Gender",
       y = "Salary",
       fill = "Gender") +
  theme_minimal()

Nach intensiven Vergleichen der Grafiken bezüglich der Salary stellt sich nun die Frage:

Ist die Gender-Pay-Gap in China doch Größer, da der größte Faktor für die Salary die Years of Experience sind?

5.3.6 Korrelationen zwischen den Spalten

Code
# Korrelation zwischen Salary und Years.Of.Experience berechnen
correlation_salary_experience <- cor(filtered_data$Salary, filtered_data$Years.Of.Experience)

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Salary und Years.Of.Experience ist:", correlation_salary_experience, "\n")
Die Korrelation zwischen Salary und Years.Of.Experience ist: 0.8103542 
Code
# Korrelation zwischen Salary und Education.Level berechnen
correlation_salary_education <- cor(filtered_data$Salary, filtered_data$Education.Level, use = "complete.obs")

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Salary und Education.Level ist:", correlation_salary_education, "\n")
Die Korrelation zwischen Salary und Education.Level ist: 0.6374551 
Code
# Korrelation zwischen Salary und Age berechnen
correlation_salary_age <- cor(filtered_data$Salary, filtered_data$Age, use = "complete.obs")

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Salary und Age ist:", correlation_salary_age, "\n")
Die Korrelation zwischen Salary und Age ist: 0.7291603 
Code
# Korrelation zwischen Years.Of.Experience und Age berechnen
correlation_experience_age <- cor(filtered_data$Years.Of.Experience, filtered_data$Age, use = "complete.obs")

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Years.Of.Experience und Age ist:", correlation_experience_age, "\n")
Die Korrelation zwischen Years.Of.Experience und Age ist: 0.9363709 
Code
# Annahme: "filtered_data" ist Ihr Datensatz
# Annahme: Die Spalten sind "Seniority" und "Years.Of.Experience"

# Korrelation zwischen Seniority und Years.Of.Experience berechnen
correlation_seniority_experience <- cor(filtered_data$Senior, filtered_data$Years.Of.Experience, use = "complete.obs")

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Seniority und Years.Of.Experience ist:", correlation_seniority_experience, "\n")
Die Korrelation zwischen Seniority und Years.Of.Experience ist: 0.3192657 

Das Ergebnis der Korrelationen:
Von Salary und Years.of.experience ist es 0.81. Von Salary und Age ist es 0.73 und die von Age und Years.Of.Experience ist 0.93.

Nun stellt sich folgende Frage: Wie kommt es zu so einem großen Unterschied Zwischen den Werten im Vergleich zu Salary, obwohl sie doch eine starke Korrelation zueinadner haben?

Mögliche Antworten auf diese Frage wären:

Verteilung der Daten:

Es ist möglich, dass die Verteilung der Daten in den Variablen “Age” und “Years.Of.Experience” anders ist als in der Variable “Salary”. Wenn die Daten in “Age” und “Years.Of.Experience” breiter gestreut sind, kann dies zu einer geringeren Korrelation führen, selbst wenn eine starke lineare Beziehung besteht.

Nicht-lineare Beziehung:

Die Korrelation misst nur lineare Beziehungen. Wenn die Beziehung zwischen “Age” und “Years.Of.Experience” nicht linear ist, könnte dies zu einem niedrigeren Korrelationswert führen.

Ausreißer:

Das Vorhandensein von Ausreißern kann die Korrelation beeinflussen. Wenn es Ausreißer in einer der Variablen gibt, kann dies den Korrelationswert beeinträchtigen.

Stichprobengröße:

Bei kleineren Stichproben können Korrelationswerte instabiler sein.

Code
# Filtern der Daten für technische und administrative Jobs basierend auf den Kriterien
technische_jobs <- subset(filtered_data, job_type == 0)
admin_jobs <- subset(filtered_data, job_type == 1)

# Durchschnittliche Gehälter pro Jobtyp für technische Jobs berechnen
average_salaries_technical <- mean(technische_jobs$Salary, na.rm = TRUE)

# Durchschnittliche Gehälter pro Jobtyp für administrative Jobs berechnen
average_salaries_admin <- mean(admin_jobs$Salary, na.rm = TRUE)

# Zusammenführen der durchschnittlichen Gehälter in einem Datenrahmen
all_average_salaries <- data.frame(Job.Type = c("technisch", "admin"),
                                   Average.Salary = c(average_salaries_technical, average_salaries_admin))

# Erstellung des Diagramms mit angepasster Achsenbeschriftung
ggplot(all_average_salaries, aes(x = Job.Type, y = Average.Salary, fill = Job.Type)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Durchschnittliche Gehälter nach Jobtyp",
       x = "Jobtyp",
       y = "Durchschnittliches Gehalt") +
  theme_minimal() +
  scale_y_continuous(labels = scales::comma)  # Verwendung von scales::comma für die Achsenbeschriftung in Tausenden

Und das Obwohl in den Admin Jobs auch direktoren und Manager vertreten sind

Nehmen wir an das Manager ein Job Titel wie Projekt Manager ist und nicht Manager für Projekte und dieser Titel in unserem Datensatz Director ist? Thema Führungsposition

Unsere Untersuchungen haben Ergeben das wir die Daten für unsere Explorative Datenanalyse aber auch die Regression neu aufbereiten müssen.

Dazu suchen wir:

Unterscheidet sich ein native und expat im jeweiligen Land? Welche Annahmen sind dafür nötig? Hier die Annahme das “White” generell nicht ausgewandert ist da wir hier Länder mit ähnlicher Kultur und Salary haben.

Code
ggplot(filtered_data, aes(x = Country, fill = Race)) +
  geom_bar(position = "dodge") +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Count of Races in Each Country",
       x = "Country",
       y = "Count") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Dafür wird eine neue Spalte eingefügt, die mit numerischen werten arbeitet. 0 steht für Einheimische und 1 für einen Expat. Den Wert null erhalten alle zeilen bei denen wir folgende Übereinstimmung feststellen: African American (USA) White (Canada, USA, UK, Australia) Chinese (China) Australian(Australia) Welsh (UK) jede andere Race ist ja dementsprechend Expat und erhält eine 1 in der Spalte Expat.

????????

Code
# Erstellen der Spalte "Expat" basierend auf den angegebenen Kriterien
filtered_data$Expat <- 0  # Standardwert 0 (Einheimische)

# Festlegen von Bedingungen für Expats basierend auf Land und Ethnizität
expat_conditions <- list(
  filtered_data$Race == "African American" & filtered_data$Country == "USA",
  filtered_data$Race %in% c("White", "Chinese", "Australian", "Welsh") &
    filtered_data$Country %in% c("Canada", "USA", "UK", "Australia"),
  TRUE  # Für alle anderen Rassen (Expat)
)

# Setzen von Werten entsprechend den Bedingungen
filtered_data$Expat <- ifelse(expat_conditions[[1]] | expat_conditions[[2]], 0, 
                               ifelse(expat_conditions[[3]], 1, NA))

# Anzeige des aktualisierten Datensatzes zur Überprüfung
head(filtered_data)
# A tibble: 6 × 14
  Job.Title    job_count   Age Gender Education.Level Years.Of.Experience Salary
  <chr>            <int> <dbl> <chr>            <dbl>               <dbl>  <dbl>
1 Back end De…       242    33 Female               2                   5 110000
2 Back end De…       242    32 Male                 1                   4  95000
3 Back end De…       242    26 Female               2                   3  90000
4 Back end De…       242    26 Female               2                   2  70000
5 Back end De…       242    24 Female               1                   1  60000
6 Back end De…       242    26 Female               2                   3  90000
# ℹ 7 more variables: Country <chr>, Race <chr>, Senior <dbl>, SalaryKat <fct>,
#   ID <int>, job_type <dbl>, Expat <dbl>

Ausgabe hier sind nun die ersten Zeilen der aktualisierten Version von “filtered_data” indem die Spalte “Expat” basierend auf den oben genannten Kriterien befüllt wurde.

6. Thesen

Aus den überlegungen der Tests und der Vorarbeit wurden folgende Thesen formuliert. Dieser Abschnitt wird in unterschiedliche Teilabschnitte geteilt.

6.1 Genderpaygap

  1. Männer verdienen mehr als Frauen
  2. Die Differenz der Salary zwischen den Geschlechtern ist in China höher als in den westlichen Ländern.
  3. Männer haben im Durchschnitt mehr Yrs of Experience als Frauen -> Lässt sich die Genderpaygap auf die Yrs of Exp übertragen? Und gilt dies auch für China

6.1.1.: Männer verdienen mehr als Frauen

Code
ggplot(filtered_data, aes(x = factor(Gender), y = Salary, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Salary vs. Gender",
       x = "Gender",
       y = "Salary",
       fill = "Gender") +
  theme_minimal()

Mithilfe des Boxplots ist zu erkennen, das der Median deutlich höher bei den Männer ist. Daraus lässt sich Schlussfolgern, dass die These Korrekt ist.

6.1.2.: Die Differenz der Salary zwischen den Geschlechtern ist in China höher als in den westlichen Ländern. Hier alle westlichen Länder hinzufügen

Code
# Daten für USA filtern
data_usa <- subset(filtered_data, Country == "USA")

# Boxplot erstellen
ggplot(data_usa, aes(x = factor(Gender), y = Years.Of.Experience, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Years of Experience vs. Gender (USA)",
       x = "Gender",
       y = "Years of Experience",
       fill = "Gender") +
  theme_minimal()

Code
# Daten für China filtern
data_china <- subset(filtered_data, Country == "China")

# Boxplot für Salary vs. Gender erstellen
ggplot(data_china, aes(x = factor(Gender), y = Salary, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Salary vs. Gender (China)",
       x = "Gender",
       y = "Salary",
       fill = "Gender") +
  theme_minimal()

These Korrekt

6.1.3.: Männer haben im Durchschnitt mehr Yrs of Experience als Frauen -> Lässt sich die Genderpaygap auf die Yrs of Exp übertragen? Und gilt dies auch für China

Code
ggplot(filtered_data, aes(x = factor(Gender), y = Years.Of.Experience, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Years of Experience vs. Gender",
       x = "Gender",
       y = "Years of Experience",
       fill = "Gender") +
  theme_minimal()

Code
# Daten für China filtern
data_china <- subset(filtered_data, Country == "China")

# Boxplot erstellen
ggplot(data_china, aes(x = factor(Gender), y = Years.Of.Experience, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Years of Experience vs. Gender (China)",
       x = "Gender",
       y = "Years of Experience",
       fill = "Gender") +
  theme_minimal()

Code
# Daten für USA filtern
data_usa <- subset(filtered_data, Country == "USA")

# Boxplot erstellen
ggplot(data_usa, aes(x = factor(Gender), y = Years.Of.Experience, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Boxplot: Years of Experience vs. Gender (USA)",
       x = "Gender",
       y = "Years of Experience",
       fill = "Gender") +
  theme_minimal()

ist jetzt der gender pay gap in china doch größer da der größte faktor für salary years of experience ist?

Dafür schauen wir uns an: Korrelation von years of experience und salary

Code
# Korrelation zwischen Salary und Years.Of.Experience berechnen
correlation_salary_experience <- cor(filtered_data$Salary, filtered_data$Years.Of.Experience)

# Ausgabe des Ergebnisses
cat("Die Korrelation zwischen Salary und Years.Of.Experience ist:", correlation_salary_experience, "\n")
Die Korrelation zwischen Salary und Years.Of.Experience ist: 0.8103542 

These Korrekt da es im gleichen Verhältnis steht. Nicht desto trotz gibt es einen Unterschied zwischen den Geschlechtern bei gleichbleibender Arbeitderfahrung was auf einen kleinen Gender Pay gap schließen lässt.

6.2 Expats verdienen mehr als Einheimisch

Unsere Untersuchungen haben Ergeben das wir die Daten für unsere Explorative Datenanalyse aber auch die Regression neu aufbereiten müssen.

Dazu suchen wir: unterscheide ich einen native und expat im jeweiligen Land. Welche annahmen sind dafür nötig? Hier die annahme das White generell nicht ausgewandert ist da wir hier länder mit ähnlicher kultur und salary haben

6.2.1.: Alle Ethnizitäten je Land

Code
ggplot(filtered_data, aes(x = Country, fill = Race)) +
  geom_bar(position = "dodge") +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Count of Races in Each Country",
       x = "Country",
       y = "Count") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Daten für Analyse von Expats und Einheimischen bereits Aufbereitet. Bitte hier nochmal beschrieben

6.2.2.: Gesamtbetrachtung

Code
# Erstellung des Boxplots für Expats und Einheimische
ggplot(filtered_data, aes(x = as.factor(Expat), y = Salary, fill = factor(Expat))) +
  geom_boxplot() +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Vergleich der Gehälter von Expats und Einheimischen",
       x = "Expat",
       y = "Gehalt") +
  scale_x_discrete(labels = c("Einheimische (0)", "Expats (1)")) +
  theme_minimal()

Code
# Mittelwert der Gehälter für Expats (Expat = 1)
mean_salary_expat <- mean(filtered_data$Salary[filtered_data$Expat == 1], na.rm = TRUE)
mean_salary_expat
[1] 116928.1
Code
# Mittelwert der Gehälter für Einheimische (Expat = 0)
mean_salary_native <- mean(filtered_data$Salary[filtered_data$Expat == 0], na.rm = TRUE)
mean_salary_native
[1] 116572.5

These verworfen. Da es offensichtlich keine Unterschiede gibt. Ggf. noch einzelne Ethnizitäten betrachten

6.3 Gehaltscap education level vorhanden?

Ohne ein Mindestmaß ein Bildung ist keine weitere Gehaltsentwicklung möglich

Bildungsniveau Codes:

0 = High School Abschluss

1 = Bachelor

2 = Master

3 = Doctor

  1. Deskriptive Statistiken: Man könnte Quantile oder Perzentile des Gehalts für jedes Bildungsniveau berechnen. Dies bietet einen Überblick über die Verteilung der Gehälter und zeigt potenzielle Grenzwerte auf.

  2. Boxplots pro Bildungsniveau: Man könnte Boxplots für jedes Bildungsniveau erstellen, um die Verteilung der Gehälter visuell zu vergleichen. Dies kann helfen, Ausreißer und Unterschiede zwischen den Bildungsniveaus zu identifizieren.

  3. Visualisierungen: Verschiedene Visualisierungen wie Scatterplots oder Liniendiagramme könnten erstellt werden, um Trends oder Muster zwischen Gehalt und Bildungsniveau zu erkennen.

6.3.1.: Desktiptive Statistiken:

Code
# Bibliotheken laden
library(ggplot2)
library(dplyr)

# Daten berechnen
salary_percentiles <- filtered_data %>%
  group_by(Education.Level) %>%
  summarise(`10th Percentile` = quantile(Salary, probs = 0.1, na.rm = TRUE),
            `25th Percentile` = quantile(Salary, probs = 0.25, na.rm = TRUE),
            `50th Percentile (Median)` = quantile(Salary, probs = 0.5, na.rm = TRUE),
            `75th Percentile` = quantile(Salary, probs = 0.75, na.rm = TRUE),
            `90th Percentile` = quantile(Salary, probs = 0.9, na.rm = TRUE))

# Reshape der Daten für das Plotting
salary_percentiles_long <- salary_percentiles %>%
  tidyr::pivot_longer(cols = -Education.Level, names_to = "Percentile", values_to = "Salary")

# Diagramm erstellen
ggplot(salary_percentiles_long, aes(x = Education.Level, y = Salary, fill = Percentile)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Perzentile des Gehalts nach Bildungsniveau",
       x = "Bildungsniveau",
       y = "Gehalt",
       fill = "Perzentil") +
  theme_minimal()

Code
# Berechnung der Durchschnittsgehälter pro Bildungsniveau
average_salary_education <- aggregate(Salary ~ Education.Level, data = filtered_data, FUN = mean, na.rm = TRUE)

# Anzeige der Durchschnittsgehälter pro Bildungsniveau
average_salary_education
  Education.Level    Salary
1               0  34511.62
2               1  97042.04
3               2 129983.77
4               3 165796.75

6.3.2.: Boxplots pro Bildungsniveau:

Code
# Bildungsniveau nach aufsteigender Reihenfolge sortieren
filtered_data <- filtered_data %>%
  mutate(Education.Level = factor(Education.Level, levels = unique(sort(Education.Level))))

# Boxplot erstellen
ggplot(filtered_data, aes(x = reorder(factor(Education.Level), Salary, FUN = median), y = Salary)) +
  geom_boxplot(color = "black", fill = viridis(2)[2]) +
  labs(title = "Boxplot des Gehalts nach Bildungsniveau",
       x = "Bildungsniveau",
       y = "Gehalt") +
  theme_minimal()

6.3.3.: Visualisierungen:

Code
# Bildungsniveau nach aufsteigender Reihenfolge sortieren
filtered_data <- filtered_data %>%
  mutate(Education.Level = factor(Education.Level, levels = unique(sort(Education.Level))))

# Scatterplot erstellen
ggplot(filtered_data, aes(x = reorder(factor(Education.Level), Salary, FUN = median), y = Salary)) +
  geom_point() + 
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Gehalt nach Bildungslevel",
       x = "Bildungslevel",
       y = "Gehalt") +
  theme_minimal()

Code
# Bildungslevel neu ordnen
filtered_data$Education.Level <- factor(filtered_data$Education.Level, levels = c("0", "1", "2", "3"))

# Liniendiagramm mit umgekehrter Reihenfolge des Bildungsniveaus erstellen
ggplot(filtered_data, aes(x = Education.Level, y = Salary, group = 1)) +
  geom_line() +
  stat_summary(fun.y = median, geom = "point", size = 3, color = "red") +
  labs(title = "Gehalt nach Bildungslevel",
       x = "Bildungslevel",
       y = "Gehalt") +
  theme_minimal()
Warning: The `fun.y` argument of `stat_summary()` is deprecated as of ggplot2 3.3.0.
ℹ Please use the `fun` argument instead.

hier diagramm erklären weil anderes aus vorlesung (Liniendiagramm)

These Korrekt: Ohne einen Hochschulabschluss gibt es eine Gehaltsgrenze. Die top 90% ohne Hochschulabschluss fangen bei den unteren 10% mit Hochschulabschluss an aus der Sicht des Gehalts.

6.4 Technische Jobs haben ein höheres Gehalt als Administrative Jobs

6.4.1.: Daten Aufbereiten

Unter dem Punkt Datenaufbereitung wurden zu diesem Zweck alle Jobs in Administrativ und Technisch eingeteilt. Zudem filtern wir noch zusätzlich alle Datensätze raus welche “Director” im Jobtitel enthalten da diese sich nicht auf eine der Kategorisieren eindeutig zuordnen lassen. (z.B. Engineering Director)

Code
# Kopie von filtered_data als filtered_data2 erstellen
filtered_data2 <- filtered_data

# Filtern der Daten für Jobs mit "Director" im Jobtitel in filtered_data2
director_jobs <- filtered_data2 %>%
  filter(grepl("Director", Job.Title))

# Entfernen der Zeilen mit "Director" aus filtered_data2
filtered_data2 <- filtered_data2 %>%
  anti_join(director_jobs)
Joining with `by = join_by(Job.Title, job_count, Age, Gender, Education.Level,
Years.Of.Experience, Salary, Country, Race, Senior, SalaryKat, ID, job_type,
Expat)`
Code
nrow(director_jobs)
[1] 416
Code
nrow(filtered_data)
[1] 6398
Code
nrow(filtered_data2)
[1] 5982

6.4.2.: Insgesamt

Eine Übersicht der durchschnittlichen Gehälter nach der Sortierung von Jobs technischer und adminsitrativer Natur.

Code
# Filtern der Daten für technische und administrative Jobs basierend auf den Kriterien
technische_jobs <- subset(filtered_data, job_type == 0)
admin_jobs <- subset(filtered_data, job_type == 1)

# Durchschnittliche Gehälter pro Jobtyp für technische Jobs berechnen
average_salaries_technical <- mean(technische_jobs$Salary, na.rm = TRUE)

# Durchschnittliche Gehälter pro Jobtyp für administrative Jobs berechnen
average_salaries_admin <- mean(admin_jobs$Salary, na.rm = TRUE)

# Zusammenführen der durchschnittlichen Gehälter in einem Datenrahmen
all_average_salaries <- data.frame(Job.Type = c("technisch", "admin"),
                                   Average.Salary = c(average_salaries_technical, average_salaries_admin))

# Erstellung des Diagramms mit angepasster Achsenbeschriftung
ggplot(all_average_salaries, aes(x = Job.Type, y = Average.Salary, fill = Job.Type)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.7) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Durchschnittliche Gehälter nach Jobtyp",
       x = "Jobtyp",
       y = "Durchschnittliches Gehalt") +
  theme_minimal() +
  scale_y_continuous(labels = scales::comma)  # Verwendung von scales::comma für die Achsenbeschriftung in Tausenden

Code
# Filtern der Daten für technische und administrative Jobs basierend auf den Kriterien
technische_jobs <- subset(filtered_data, job_type == 0)
admin_jobs <- subset(filtered_data, job_type == 1)

# Durchschnittliche Gehälter pro Jobtyp für technische Jobs berechnen
average_salaries_technical <- mean(technische_jobs$Salary, na.rm = TRUE)

# Durchschnittliche Gehälter pro Jobtyp für administrative Jobs berechnen
average_salaries_admin <- mean(admin_jobs$Salary, na.rm = TRUE)

# Ausgabe der berechneten durchschnittlichen Gehälter mit Beschriftung
cat("Durchschnittliches Gehalt für technische Jobs:", average_salaries_technical, "\n")
Durchschnittliches Gehalt für technische Jobs: 126441.3 
Code
cat("Durchschnittliches Gehalt für administrative Jobs:", average_salaries_admin, "\n")
Durchschnittliches Gehalt für administrative Jobs: 101595.3 

6.4.3.: Je Land

Eine Übersicht der durchschnittlichen Gehälter nach der Sortierung von Jobs technischer und adminsitrativer Natur aller Länder.

Code
#Daten nach Bildungsniveau, Land und Median des Gehalts gruppieren
summary_data <- aggregate(Salary ~ Education.Level + Country, data = filtered_data, FUN = median)

#Balkendiagramm erstellen
ggplot(summary_data, aes(x = Education.Level, y = Salary, fill = Country)) +
  geom_bar(stat = "identity", position = "dodge") +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Median Gehalt nach Bildungslevel und Land", 
       x = "Bildungslevel",
       y = "Median Gehalt",
       fill = "Land") +
  theme_minimal()

These Korrekt, und das Obwohl in den Admin Jobs auch in seltenen Fällen Manager vertreten sind.

Es lässt sich zudem beobachten das Doktoren in Australien ein höheres Gehalt verdienen als in anderen Ländern.

6.5 Data Scientist verdienen aufgrund der hohen Nachfrage der Berufsgruppe im Schnitt mehr Geld als andere Jobgruppen bei gleichbleibender Erfahrung und Abschlussniveau.

6.5.1.: Begründung

Data Scientist ist laut dem Harvard Business Review der “Sexiest Job of the 21st Century”*

*https://hbr.org/2012/10/data-scientist-the-sexiest-job-of-the-21st-century

Bei dieser Aussage haben wir uns gefragt ob sich die Beschreibung auch auf die Gehälter des Data Scientists anwenden lässt.

2.: Datenaufbereitung

Rausfiltern aller Manager und Direktoren. Einengung nach Jobs mit dem Stichwort Data, Software, Developer und Engineer

Code
# Filtern der Daten für Jobs mit spezifischen Schlüsselwörtern im Jobtitel
filtered_data3 <- filtered_data %>%
  filter(grepl("Data|Software|Developer|Engineer", Job.Title))

# Anzeigen aller eindeutigen Jobtitel und deren Häufigkeit in filtered_data3
job_title_count <- table(filtered_data3$Job.Title)
job_title_df <- data.frame(Job_Title = names(job_title_count), Frequency = as.numeric(job_title_count))

# Anzeige des Dataframes mit den Jobtiteln und deren Häufigkeit
job_title_df
                   Job_Title Frequency
1         Back end Developer       242
2               Data Analyst       391
3             Data Scientist       515
4   Director of Data Science        57
5        Front end Developer       239
6        Front End Developer        31
7        Full Stack Engineer       304
8           Project Engineer       317
9         Software Developer       186
10         Software Engineer       809
11 Software Engineer Manager       376
12             Web Developer       129
Code
# Filtern der Daten für Jobs ohne "Director" im Jobtitel
filtered_data3 <- filtered_data3 %>%
  filter(!grepl("Director|Manager", Job.Title))

# Anzeigen aller eindeutigen Jobtitel und deren Häufigkeit in filtered_data3
job_title_count <- table(filtered_data3$Job.Title)
job_title_df <- data.frame(Job_Title = names(job_title_count), Frequency = as.numeric(job_title_count))

# Anzeige des Dataframes mit den Jobtiteln und deren Häufigkeit
job_title_df
             Job_Title Frequency
1   Back end Developer       242
2         Data Analyst       391
3       Data Scientist       515
4  Front end Developer       239
5  Front End Developer        31
6  Full Stack Engineer       304
7     Project Engineer       317
8   Software Developer       186
9    Software Engineer       809
10       Web Developer       129

Aufteilen der Jobs in die Sparte Data & Software

Code
# Erstellen der neuen Spalte 'data_job'
filtered_data3 <- filtered_data3 %>%
  mutate(data_job = ifelse(grepl("Data", Job.Title), 1, 0))
Code
# Zählen der Anzahl von 0 und 1 in der Spalte data_job
count_0 <- sum(filtered_data3$data_job == 0, na.rm = TRUE)
count_1 <- sum(filtered_data3$data_job == 1, na.rm = TRUE)

# Ausgabe der Anzahl von 0 und 1
cat("Anzahl der Zeilen mit dem Wert 0 bei data_job (Data Scientists & Engineers):", count_0, "\n")
Anzahl der Zeilen mit dem Wert 0 bei data_job (Data Scientists & Engineers): 2257 
Code
cat("Anzahl der Zeilen mit dem Wert 1 bei data_job (Software Engineers & Co):", count_1, "\n")
Anzahl der Zeilen mit dem Wert 1 bei data_job (Software Engineers & Co): 906 

6.5.3.: Balkendiagramm

Hierzu teilen wir noch die Arbeitserfahrung in Quartile ein für eine bessere Übersicht. Die Bildungsniveaus sind ja bereits in 4 Werte Unterteilt.

Ich weiß nicht warum aber ich muss das Paket neu laden.

Code
# Berechnung der Quartile der Berufserfahrung
filtered_data4 <- filtered_data3 %>%
  mutate(Experience_Quartile = ntile(Years.Of.Experience, 4))

# Balkendiagramm für data_job im Vergleich zum Gehalt
ggplot(filtered_data4, aes(x = factor(data_job), y = Salary)) +
  stat_summary(fun = "mean", geom = "bar", position = "dodge", fill = viridis(2)[1]) +
  labs(title = "Gehalt nach Data Job",
       x = "Data Job",
       y = "Gehalt (Mittelwert)")

Code
# Erstellung des Balkendiagramms
ggplot(filtered_data4, aes(y = Salary, x = factor(Experience_Quartile))) +
  geom_bar(stat = "identity", position = "dodge", aes(fill = factor(data_job))) +
  labs(title = "Quartile der Berufserfahrung nach Gehalt und Jobtyp",
       x = "Quartile der Berufserfahrung",
       y = "Gehalt") +
  theme_minimal() +
  scale_fill_viridis(discrete = TRUE)

Bildungsniveau Codes:

0 = High School Abschluss

1 = Bachelor

2 = Master

3 = Doctor

Code
# Erstellung des Balkendiagramms für Education Level
ggplot(filtered_data4, aes(y = Salary, x = factor(Education.Level))) +
  geom_bar(stat = "identity", position = "dodge", aes(fill = factor(data_job))) +
  scale_fill_viridis(discrete = TRUE) +
  labs(title = "Quartile des Bildungsniveaus nach Gehalt und Jobtyp",
       x = "Quartile des Bildungsniveaus",
       y = "Gehalt") +
  theme_minimal()

Im Mittel verdienen Data Scientists mehr als Arbeitnehmer aus der Software Engineering & Co Gruppe. Wobei man beobachten kann das die Gruppe Data mindestens einen Bachelor bestitzt und erst ab dem Master mehr verdient als ihr counterpart. Bezüglich der Berufserfahrung lässt sich feststellen das es in jedem Quartil ein höheres Gehaltsniveau bei der Gruppe Data gibt.

6.6 Die Gehälter sind höher in Ländern mit höheren BIP pro Kopf

Da dieses Land staistisch mehr Geld pro Einwohner erwirtschaftet.

BIP pro Kopf (2023):

Australien 64.813,85 US-Dollar Quelle: Australien - BIP pro Kopf bis 2028 | Statista

Canada 53.246,98 US-Dollar Quelle: Kanada - BIP pro Kopf bis 2028 | Statista

China 12.541,40 US-Dollar Quelle: China - BIP pro Kopf bis 2028 | Statista

UK 48.912,78 US-Dollar Quelle: Großbritannien - BIP pro Kopf bis 2028 | Statista

USA 76.343 US-Dollar Quelle: USA - BIP pro Kopf bis 2028 | Statista

6.6.1.: Aufbereitung

Code
# Erstelle eine neue Spalte "BIP_Per_Person" mit NA-Werten
filtered_data3$BIP_Per_Person <- NA

# Weise den genannten Ländern die entsprechenden BIP-Werte zu
filtered_data3$BIP_Per_Person[filtered_data3$Country == "Australia"] <- 64813.85
filtered_data3$BIP_Per_Person[filtered_data3$Country == "Canada"] <- 53246.98
filtered_data3$BIP_Per_Person[filtered_data3$Country == "China"] <- 12541.40
filtered_data3$BIP_Per_Person[filtered_data3$Country == "UK"] <- 48912.78
filtered_data3$BIP_Per_Person[filtered_data3$Country == "USA"] <- 76343.00
Code
head(filtered_data3)
# A tibble: 6 × 16
  Job.Title    job_count   Age Gender Education.Level Years.Of.Experience Salary
  <chr>            <int> <dbl> <chr>  <fct>                         <dbl>  <dbl>
1 Back end De…       242    33 Female 2                                 5 110000
2 Back end De…       242    32 Male   1                                 4  95000
3 Back end De…       242    26 Female 2                                 3  90000
4 Back end De…       242    26 Female 2                                 2  70000
5 Back end De…       242    24 Female 1                                 1  60000
6 Back end De…       242    26 Female 2                                 3  90000
# ℹ 9 more variables: Country <chr>, Race <chr>, Senior <dbl>, SalaryKat <fct>,
#   ID <int>, job_type <dbl>, Expat <dbl>, data_job <dbl>, BIP_Per_Person <dbl>

Hat funktioniert.

6.6.2.: Scatterplot

Code
# Scatterplot mit Farbgebung nach Ländern und Mittelwerten einzeichnen
ggplot(filtered_data3, aes(x = BIP_Per_Person, y = Salary, color = Country)) +
  geom_point() +
  stat_summary(fun = mean, geom = "point", shape = 23, size = 3, fill = "black") +
  labs(title = "Vergleich von Gehalt und BIP pro Person nach Ländern",
       x = "BIP pro Person",
       y = "Gehalt",
       color = "Land") +
  scale_color_viridis(discrete = TRUE)

Code
# Berechnung der Mittelwerte nach Land
mean_salaries_by_country <- filtered_data3 %>%
  group_by(Country) %>%
  summarise(mean_salary = mean(Salary, na.rm = TRUE))

# Ausgabe der Mittelwerte nach Land
mean_salaries_by_country
# A tibble: 5 × 2
  Country   mean_salary
  <chr>           <dbl>
1 Australia     121610.
2 Canada        125466.
3 China         120395.
4 UK            123564.
5 USA           119265.
Code
# Berechnung der Mittelwerte nach Land
mean_salaries_by_country <- filtered_data3 %>%
  group_by(Country) %>%
  summarise(mean_salary = mean(Salary, na.rm = TRUE),
            BIP_Per_Person = first(BIP_Per_Person))  # Annahme: BIP-Pro-Person-Werte sind konstant für jedes Land

# Ausgabe der Mittelwerte nach Land mit BIP pro Person
mean_salaries_by_country
# A tibble: 5 × 3
  Country   mean_salary BIP_Per_Person
  <chr>           <dbl>          <dbl>
1 Australia     121610.         64814.
2 Canada        125466.         53247.
3 China         120395.         12541.
4 UK            123564.         48913.
5 USA           119265.         76343 
Code
cor(filtered_data3$Salary, filtered_data3$BIP_Per_Person, use = "complete.obs")
[1] -0.00247782

Nun ohne China

Code
# Erstellen des neuen Datensatzes ohne Einträge für China
filtered_data3_no_china <- filtered_data3 %>% filter(Country != "China")
Code
cor(filtered_data3_no_china$Salary, filtered_data3_no_china$BIP_Per_Person, use = "complete.obs")
[1] -0.04303227
Code
# Anzahl der Datensätze mit dem Land "China" im Datensatz filtered_data3_no_china
count_china <- filtered_data3_no_china %>% filter(Country == "China") %>% nrow()
count_china
[1] 0

These nicht korrekt. Es scheint so als gibt es eine negative Korrelation zwischen dem Gehalt welches ein Arbeitnehmer erhält und dem BIP des jeweiligen Landes. Selbst wenn man China aus der Rechnung rausnimmt welches aufgrund der ungewöhnlich hohen Einwohnerzahl und diversen Wirtschaft (Sonderverwaltungszonen und Kommunismus*) einen sehr niedrigen BIP hat aber trotzdem hohe Gehälter.

Wurden eventuell im Datensatz eventuell bewusst Jobs mit hohem Gehalt gewählt? Oder Von Spezifischen Firmen die international Tätig sind und gut bezahlen?

*https://de.wikipedia.org/wiki/Politisches_System_der_Volksrepublik_China

*https://de.wikipedia.org/wiki/Sonderverwaltungszone

7. Regressionen

7.1.: Gehalt und Arbeitserfahrung

QQ Plot der Residuen gibt extra Punkte DAML Folien 3 Seite 10. Hinweise 2.4 S.10

Prüfung der Modellprämissen Punkt 5. Prüfung ist erklärt im Regressionsbeispiel im fall Umfangreiches Beispiel mit Prüfung des Modellprämissen

Die Korrelation von Arbeitserfahtung und Gehalt liegt bei 0.81 weshalb wir uns entscheiden haben diese als Regression zu verwenden. Des weiteren nutzen wir auch das Alter so wie das Bildungsniveau.

Code
filtered_data3 %>%
  ggplot() +
  aes(x = Salary, y = Years.Of.Experience) +
  geom_point(aes(color = Salary), alpha = 0.8) +
  geom_smooth(method = lm, color = "orange") +
  scale_color_viridis(option = "D")
`geom_smooth()` using formula = 'y ~ x'

Rausnehmen aller nicht für die Regression relevanten Werte:

Code
# Nur 'Salary' und 'Years.Of.Experience' behalten und den Rest entfernen
filtered_data5 <- filtered_data3 %>%
  select(Salary, Years.Of.Experience)

Zuerst führen wir dazu eine Z-Skalierung von filtered_data_5 durch.

Die Z-Skalierung ist eine Methode zur Standardisierung von numerischen Variablen, die in der linearen Regression und Entscheidungsbaum-Modellierung verwendet wird. Bei der Z-Skalierung werden alle numerischen Werte mit Ausnahme des Vorhersagewerts skaliert, um die Auswirkungen von Ausreißern zu minimieren und die Konvergenzgeschwindigkeit des Gradientenabstiegs zu erhöhen.

Code
# Z-Skalierung der Variable "Years.Of.Experience"
filtered_data5_z <- filtered_data5
filtered_data5_z$Years.Of.Experience <- scale(filtered_data5$Years.Of.Experience)

Ergebnis der Z-Skalierung:

Code
summary(filtered_data5_z)
     Salary       Years.Of.Experience.V1
 Min.   :   550   Min.   :-1.270088     
 1st Qu.: 80000   1st Qu.:-0.771345     
 Median :122581   Median :-0.272603     
 Mean   :122056   Mean   : 0.000000     
 3rd Qu.:160000   3rd Qu.: 0.392387     
 Max.   :240000   Max.   : 4.216080     

Überprüfung der Standardabweichung für Arbeitserfahrung

Code
sd(filtered_data5_z$Years.Of.Experience)
[1] 1

Aufteilung in Test- und Trainingsdaten:

Code
set.seed(007)

filtered_data5_z <- initial_split(filtered_data5_z, prop = 0.8, strata = Years.Of.Experience)

fd5_train <- training(filtered_data5_z)
fd5_test <- testing(filtered_data5_z)

Dieser Code teilt den Datensatz filtered_data5_z in Trainings- und Testdaten auf, um eine lineare Regression durchzuführen. Die Funktion set.seed(007) initialisiert den Zufallszahlengenerator mit einer festen Zahl, um sicherzustellen, dass die Ergebnisse bei jedem Durchlauf reproduzierbar sind. Die Funktion initial_split() aus dem Paket rsample teilt den Datensatz in Trainings- und Testdaten auf. Der Parameter prop = 0,8 gibt an, dass 80% der Daten für das Training verwendet werden sollen, während die restlichen 20% für das Testen verwendet werden. Der Parameter strata = Years.Of.Experience sorgt dafür, dass die Daten nach dem Gehalts-Wert stratifiziert werden, um sicherzustellen, dass die Trainings- und Testdaten eine ähnliche Verteilung von Gehalts-Werten aufweisen. Die Funktion training() extrahiert die Trainingsdaten aus dem aufgeteilten Datensatz, während testing() die Testdaten extrahiert.

Modell Initialisieren:

Code
# Modell initialisieren
lm_model <- linear_reg() |> set_engine("lm")

Lineare Regression:

Code
# Lineare Regression von "Salary" basierend auf "Years.Of.Experience"
lm_fit <- lm_model |> fit(Salary ~ Years.Of.Experience, data = fd5_train)

Zusammenfassung des Ergebnis:

Code
# Zusammenfassung der Regression
summary <- lm_fit |> extract_fit_engine() |> summary()
summary

Call:
stats::lm(formula = Salary ~ Years.Of.Experience, data = data)

Residuals:
    Min      1Q  Median      3Q     Max 
-134867  -23921   -4848   18206   82152 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)         121752.5      622.4  195.60   <2e-16 ***
Years.Of.Experience  36199.2      628.4   57.61   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 31300 on 2527 degrees of freedom
Multiple R-squared:  0.5677,    Adjusted R-squared:  0.5675 
F-statistic:  3319 on 1 and 2527 DF,  p-value: < 2.2e-16

Hier alles erklären danke.

Vorhersagen auf Trainings- und Testdatensatz:

Code
pred_train <- predict(lm_fit, new_data = fd5_train) |> rename("pred_train" = ".pred")
pred_test <- predict(lm_fit, new_data = fd5_test) |>  rename("pred_test" = ".pred")

compare_train <- fd5_train |> 
  select(Salary) |> 
  bind_cols(pred_train)
head(compare_train)
# A tibble: 6 × 2
  Salary pred_train
   <dbl>      <dbl>
1  90000     93830.
2  70000     87812.
3  60000     81794.
4  90000     93830.
5  60000     81794.
6  85000     93830.
Code
compare_test <- fd5_test |> 
  select(Salary) |> 
  bind_cols(pred_test)
head(compare_test)
# A tibble: 6 × 2
  Salary pred_test
   <dbl>     <dbl>
1 110000   105866.
2  75000    87812.
3  95000    99848.
4  90000    93830.
5  70000    87812.
6  95000    99848.

Grafische Darstellung:

Code
# Daten für Training und Test
train_data <- cbind(fd5_train, pred_train)
test_data <- cbind(fd5_test, pred_test)

# Erstellen Sie eine ggplot-Grafik für die Trainingsdaten
ggplot(train_data, aes(x = Years.Of.Experience, y = Salary)) +
  geom_point(color = viridis(0.50), alpha = 0.5) +
  geom_line(aes(y = pred_train), color = "deeppink3", size = 1) +
  labs(title = "Vorhersage auf Trainingsdaten",
       x = "Years of Experience",
       y = "Salary") +
  scale_color_identity() +  # Farben beibehalten
  scale_y_continuous(labels = scales::comma) +
  theme_minimal()
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.

Code
# Erstellen Sie eine ggplot-Grafik für die Testdaten
ggplot(test_data, aes(x = Years.Of.Experience, y = Salary)) +
  geom_point(color = viridis(0.50), alpha = 0.5) +
  geom_line(aes(y = pred_test), color = "deeppink3", size = 1) +
  labs(title = "Vorhersage auf Testdaten",
       x = "Years of Experience",
       y = "Salary") +
  scale_color_identity() +  # Farben beibehalten
  scale_y_continuous(labels = scales::comma) +
  theme_minimal()

Trainingsfehler:

Code
rmse(compare_train, Salary, pred_train)
# A tibble: 1 × 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 rmse    standard      31290.

Testfehler:

Code
rmse(compare_test, Salary, pred_test)
# A tibble: 1 × 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 rmse    standard      32154.

Verteilung von Arbeitserfahrung:

Code
describe(filtered_data5, Salary)
variable = Salary
type     = double
na       = 0 of 3 163 (0%)
unique   = 334
min|max  = 550 | 240 000
q05|q95  = 50 000 | 190 000
q25|q75  = 80 000 | 160 000
median   = 122 581
mean     = 122 055.8

Residuen

Residuen (auch als Fehler oder Residuals bezeichnet) sind die Differenzen zwischen den beobachteten Werten und den vorhergesagten Werten in einem Regressionsmodell. Sie repräsentieren die Abweichungen zwischen den tatsächlichen Daten und den Werten, die das Modell vorhersagt. Idealerweise sollten die Residuen normalverteilt sein, um sicherzustellen, dass das Regressionsmodell angemessen ist.

Es ist üblich, die Residuen sowohl für Trainingsdaten als auch für Testdaten zu überprüfen, um die Leistung des Modells auf beiden Datensätzen zu evaluieren. Hier sind einige Gründe, warum es wichtig ist, die Residuen auf beiden Datensätzen zu betrachten:

  1. Trainingsdaten:

    • Die Residuen der Trainingsdaten geben Ihnen einen Einblick in die Leistung des Modells auf den Daten, auf denen es trainiert wurde. Wenn die Residuen auf den Trainingsdaten ungewöhnliche Muster aufweisen, kann dies auf Modellprobleme oder Overfitting hinweisen.
  2. Testdaten:

    • Die Residuen der Testdaten ermöglichen es Ihnen, die Generalisierungsfähigkeit des Modells auf neuen, nicht trainierten Daten zu überprüfen. Ein Modell kann auf den Trainingsdaten gut funktionieren, aber die Residuen auf den Testdaten können Ihnen sagen, wie gut es sich auf unbekannte Daten verallgemeinert.

In Ihrer speziellen Situation könnten Sie die Residuen für beide Datensätze betrachten, indem Sie die augment()-Funktion für Trainings- und Testdaten separat aufrufen, wie im vorherigen Beispiel gezeigt.

Code
# Residuen mit augment() auf den Trainingsdaten abrufen
residuals_train <- augment(lm_fit, new_data = fd5_train) %>% select(.resid)

# Residuen mit augment() auf den Testdaten abrufen
residuals_test <- augment(lm_fit, new_data = fd5_test) %>% select(.resid)

# Ausgabe der Residuen für Trainingsdaten
print(residuals_train)
# A tibble: 2,529 × 1
    .resid
     <dbl>
 1  -3830.
 2 -17812.
 3 -21794.
 4  -3830.
 5 -21794.
 6  -8830.
 7 -26794.
 8 -21794.
 9 -26794.
10 -17812.
# ℹ 2,519 more rows
Code
# Ausgabe der Residuen für Testdaten
print(residuals_test)
# A tibble: 634 × 1
    .resid
     <dbl>
 1   4134.
 2 -12812.
 3  -4848.
 4  -3830.
 5 -17812.
 6  -4848.
 7 -21794.
 8 -17812.
 9 -17812.
10   8115.
# ℹ 624 more rows

Histogramm der Residuen

Code
# Standardisierung/Z-Skalierung der Residuen der Residuen
residuals_train$standardized_resid <- scale(residuals_train$.resid)

# Histogramm der standardisierten Residuen mit Viridis-Farbschema
ggplot(data = residuals_train, aes(x = standardized_resid)) +
  geom_histogram(binwidth = 0.5, fill = viridis(1), color = "black", alpha = 0.7) +
  labs(title = "Histogramm der standardisierten Residuen",
       x = "Standardisierte Residuen",
       y = "Häufigkeit") +
  scale_fill_viridis() +  # Fügt das Viridis-Farbschema hinzu
  theme_minimal()

Code
# Standardisierung/Z-Skalierung der Residuen der Residuen
residuals_test$standardized_resid <- scale(residuals_test$.resid)

# Histogramm der standardisierten Residuen mit Viridis-Farbschema
ggplot(data = residuals_test, aes(x = standardized_resid)) +
  geom_histogram(binwidth = 0.5, fill = viridis(1), color = "black", alpha = 0.7) +
  labs(title = "Histogramm der standardisierten Residuen",
       x = "Standardisierte Residuen",
       y = "Häufigkeit") +
  scale_fill_viridis() +  # Fügt das Viridis-Farbschema hinzu
  theme_minimal()

Q-Q-Plot

(Quantil-Quantil-Diagramm): überprüft die Residuen auf Normalverteilung. Die Quantile der standardisierten Residuen werden gegen die Quantile der Normalverteilung geplottet. Unter der Normalitätsannahme sollten die Punkte zufällig entlang der Diagonale (x=y) streuen (Umschreiben)

Trainingsdaten

Code
# QQ-Plot erstellen
ggplot(data = residuals_train, aes(sample = standardized_resid)) +
  stat_qq(distribution = qnorm, dparams = list(mean = 0, sd = 1), color = viridis(1)) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "black") +
  labs(title = "QQ-Plot der standardisierten Residuen",
       x = "Quantile der Normalverteilung",
       y = "Quantile der Residuen") +
  scale_color_viridis() +  # Fügt das Viridis-Farbschema hinzu
  theme_minimal()

Testdaten

Code
residuals_test$standardized_resid <- scale(residuals_test$.resid)
# QQ-Plot erstellen
ggplot(data = residuals_test, aes(sample = standardized_resid)) +
  stat_qq(distribution = qnorm, dparams = list(mean = 0, sd = 1), color = viridis(1)) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "black") +
  labs(title = "QQ-Plot der standardisierten Residuen",
       x = "Quantile der Normalverteilung",
       y = "Quantile der Residuen") +
  scale_color_viridis() +  # Fügt das Viridis-Farbschema hinzu
  theme_minimal()

Bildet die ausreißer vom Gehalt nach oben und unten ab welche wir im ersten Diagramm von 7.1 sehen, die Residuen sind nicht perfekt normalverteilt. Eventuell gibt es hier Datenpunkte welche die Residuen beeinflussen. Aufgrund der explorativen Datenanalyse wissen wir das Jobs mit hoher Arbeitserfahrung oft Führungsverantwortung beinhalten welche nochmal zusätzlich monetär honoriert wird. Die Flache Linie durch die Gerade durch deutet auf ein Gehaltscap hin. Die Ausreißer am unteren Ende lassen sich durch Einstiegsjobs so wie Niedriglohnjobs ohne Hochschulabchlüsse erklären. (Ausbildungsberufe werden hier nicht berücksichtigt).

7.2.:

8. Abschluss

8.1.: Kritik

Hätte man alle Betrachtungen under der gleichstellung von Years of Experience und Education level betrachten sollen bei länder und geschlechter vergleichen?